From: Florian Müllner Date: Sun, 7 Jul 2019 21:38:27 +0000 (+0200) Subject: extensionSystem: Move extension loading into ExtensionManager X-Git-Tag: archive/raspbian/50.5-1+rpi1~1^2~845^2^2~3 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=1d6ddf060b8672481eda6d673d064b9cdc2bb1ba;p=gnome-shell.git extensionSystem: Move extension loading into ExtensionManager Now that extension loading and the extensions map are no longer shared between the gnome-shell and gnome-shell-extension-prefs processes, we can move both into the ExtensionManager which makes much more sense conceptually. https://bugzilla.gnome.org/show_bug.cgi?id=789852 --- diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js index 96431b1f2..d17aee9fb 100644 --- a/js/misc/extensionUtils.js +++ b/js/misc/extensionUtils.js @@ -7,10 +7,8 @@ const { Gio, GLib } = imports.gi; const Gettext = imports.gettext; const Lang = imports.lang; -const Signals = imports.signals; const Config = imports.misc.config; -const FileUtils = imports.misc.fileUtils; var ExtensionType = { SYSTEM: 1, @@ -32,9 +30,6 @@ var ExtensionState = { const SERIALIZED_PROPERTIES = ['type', 'state', 'path', 'error', 'hasPrefs', 'canChange']; -// Maps uuid -> metadata object -var extensions = {}; - /** * getCurrentExtension: * @@ -65,13 +60,17 @@ function getCurrentExtension() { if (!match) return null; + // local import, as the module is used from outside the gnome-shell process + // as well (not this function though) + let extensionManager = imports.ui.main.extensionManager; + let path = match[1]; let file = Gio.File.new_for_path(path); // Walk up the directory tree, looking for an extension with // the same UUID as a directory name. while (file != null) { - let extension = extensions[file.get_basename()]; + let extension = extensionManager.extensions[file.get_basename()]; if (extension !== undefined) return extension; file = file.get_parent(); @@ -177,55 +176,6 @@ function isOutOfDate(extension) { return false; } -function createExtensionObject(uuid, dir, type) { - let metadataFile = dir.get_child('metadata.json'); - if (!metadataFile.query_exists(null)) { - throw new Error('Missing metadata.json'); - } - - let metadataContents, success, tag; - try { - [success, metadataContents, tag] = metadataFile.load_contents(null); - if (metadataContents instanceof Uint8Array) - metadataContents = imports.byteArray.toString(metadataContents); - } catch (e) { - throw new Error(`Failed to load metadata.json: ${e}`); - } - let meta; - try { - meta = JSON.parse(metadataContents); - } catch (e) { - throw new Error(`Failed to parse metadata.json: ${e}`); - } - - let requiredProperties = ['uuid', 'name', 'description', 'shell-version']; - for (let i = 0; i < requiredProperties.length; i++) { - let prop = requiredProperties[i]; - if (!meta[prop]) { - throw new Error(`missing "${prop}" property in metadata.json`); - } - } - - if (uuid != meta.uuid) { - throw new Error(`uuid "${meta.uuid}" from metadata.json does not match directory name "${uuid}"`); - } - - let extension = {}; - - extension.metadata = meta; - extension.uuid = meta.uuid; - extension.type = type; - extension.dir = dir; - extension.path = dir.get_path(); - extension.error = ''; - extension.hasPrefs = dir.get_child('prefs.js').query_exists(null); - extension.canChange = false; - - extensions[uuid] = extension; - - return extension; -} - function serializeExtension(extension) { let obj = {}; Lang.copyProperties(extension.metadata, obj); @@ -280,36 +230,3 @@ function installImporter(extension) { extension.imports = imports[extension.uuid]; imports.searchPath = oldSearchPath; } - -var ExtensionFinder = class { - _loadExtension(extensionDir, info, perUserDir) { - let fileType = info.get_file_type(); - if (fileType != Gio.FileType.DIRECTORY) - return; - let uuid = info.get_name(); - let existing = extensions[uuid]; - if (existing) { - log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path())); - return; - } - - let extension; - let type = extensionDir.has_prefix(perUserDir) ? ExtensionType.PER_USER - : ExtensionType.SYSTEM; - try { - extension = createExtensionObject(uuid, extensionDir, type); - } catch (e) { - logError(e, 'Could not load extension %s'.format(uuid)); - return; - } - this.emit('extension-found', extension); - } - - scanExtensions() { - let perUserDir = Gio.File.new_for_path(global.userdatadir); - FileUtils.collectFromDatadirs('extensions', true, (dir, info) => { - this._loadExtension(dir, info, perUserDir); - }); - } -}; -Signals.addSignalMethods(ExtensionFinder.prototype); diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js index aa5d7b94d..ca9de0e18 100644 --- a/js/ui/extensionDownloader.js +++ b/js/ui/extensionDownloader.js @@ -44,7 +44,7 @@ function installExtension(uuid, invocation) { } function uninstallExtension(uuid) { - let extension = ExtensionUtils.extensions[uuid]; + let extension = Main.extensionManager.extensions[uuid]; if (!extension) return false; @@ -113,7 +113,7 @@ function updateExtension(uuid) { _httpSession.queue_message(message, (session, message) => { gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, () => { - let oldExtension = ExtensionUtils.extensions[uuid]; + let oldExtension = Main.extensionManager.extensions[uuid]; let extensionDir = oldExtension.dir; if (!Main.extensionManager.unloadExtension(oldExtension)) @@ -125,7 +125,7 @@ function updateExtension(uuid) { let extension = null; try { - extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER); + extension = Main.extensionManager.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER); Main.extensionManager.loadExtension(extension); } catch (e) { if (extension) @@ -151,8 +151,8 @@ function updateExtension(uuid) { function checkForUpdates() { let metadatas = {}; - for (let uuid in ExtensionUtils.extensions) { - metadatas[uuid] = ExtensionUtils.extensions[uuid].metadata; + for (let uuid in Main.extensionManager.extensions) { + metadatas[uuid] = Main.extensionManager.extensions[uuid].metadata; } let params = { shell_version: Config.PACKAGE_VERSION, @@ -225,7 +225,7 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog { function callback() { try { - let extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER); + let extension = Main.extensionManager.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER); Main.extensionManager.loadExtension(extension); if (!Main.extensionManager.enableExtension(uuid)) throw new Error(`Cannot add ${uuid} to enabled extensions gsettings key`); diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js index 6d842dc16..ba1d12a4e 100644 --- a/js/ui/extensionSystem.js +++ b/js/ui/extensionSystem.js @@ -4,9 +4,10 @@ const { Gio, St } = imports.gi; const Signals = imports.signals; const ExtensionUtils = imports.misc.extensionUtils; +const FileUtils = imports.misc.fileUtils; const Main = imports.ui.main; -const { ExtensionState } = ExtensionUtils; +const { ExtensionState, ExtensionType } = ExtensionUtils; const ENABLED_EXTENSIONS_KEY = 'enabled-extensions'; const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions'; @@ -17,15 +18,23 @@ var ExtensionManager = class { this._initted = false; this._enabled = false; + this._extensions = {}; this._enabledExtensions = []; this._extensionOrder = []; Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); + } + + init() { this._sessionUpdated(); } + get extensions() { + return this._extensions; + } + _callExtensionDisable(uuid) { - let extension = ExtensionUtils.extensions[uuid]; + let extension = this._extensions[uuid]; if (!extension) return; @@ -47,7 +56,7 @@ var ExtensionManager = class { for (let i = 0; i < orderReversed.length; i++) { let uuid = orderReversed[i]; try { - ExtensionUtils.extensions[uuid].stateObj.disable(); + this._extensions[uuid].stateObj.disable(); } catch (e) { this.logExtensionError(uuid, e); } @@ -68,7 +77,7 @@ var ExtensionManager = class { for (let i = 0; i < order.length; i++) { let uuid = order[i]; try { - ExtensionUtils.extensions[uuid].stateObj.enable(); + this._extensions[uuid].stateObj.enable(); } catch (e) { this.logExtensionError(uuid, e); } @@ -83,7 +92,7 @@ var ExtensionManager = class { } _callExtensionEnable(uuid) { - let extension = ExtensionUtils.extensions[uuid]; + let extension = this._extensions[uuid]; if (!extension) return; @@ -127,7 +136,7 @@ var ExtensionManager = class { } enableExtension(uuid) { - if (!ExtensionUtils.extensions[uuid]) + if (!this._extensions[uuid]) return false; let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); @@ -140,7 +149,7 @@ var ExtensionManager = class { } disableExtension(uuid) { - if (!ExtensionUtils.extensions[uuid]) + if (!this._extensions[uuid]) return false; let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); @@ -153,7 +162,7 @@ var ExtensionManager = class { } logExtensionError(uuid, error) { - let extension = ExtensionUtils.extensions[uuid]; + let extension = this._extensions[uuid]; if (!extension) return; @@ -169,6 +178,54 @@ var ExtensionManager = class { this.emit('extension-state-changed', extension); } + createExtensionObject(uuid, dir, type) { + let metadataFile = dir.get_child('metadata.json'); + if (!metadataFile.query_exists(null)) { + throw new Error('Missing metadata.json'); + } + + let metadataContents, success; + try { + [success, metadataContents] = metadataFile.load_contents(null); + if (metadataContents instanceof Uint8Array) + metadataContents = imports.byteArray.toString(metadataContents); + } catch (e) { + throw new Error(`Failed to load metadata.json: ${e}`); + } + let meta; + try { + meta = JSON.parse(metadataContents); + } catch (e) { + throw new Error(`Failed to parse metadata.json: ${e}`); + } + + let requiredProperties = ['uuid', 'name', 'description', 'shell-version']; + for (let i = 0; i < requiredProperties.length; i++) { + let prop = requiredProperties[i]; + if (!meta[prop]) { + throw new Error(`missing "${prop}" property in metadata.json`); + } + } + + if (uuid != meta.uuid) { + throw new Error(`uuid "${meta.uuid}" from metadata.json does not match directory name "${uuid}"`); + } + + let extension = { + metadata: meta, + uuid: meta.uuid, + type, + dir, + path: dir.get_path(), + error: '', + hasPrefs: dir.get_child('prefs.js').query_exists(null), + canChange: false + }; + this._extensions[uuid] = extension; + + return extension; + } + loadExtension(extension) { // Default to error, we set success as the last step extension.state = ExtensionState.ERROR; @@ -202,7 +259,7 @@ var ExtensionManager = class { extension.state = ExtensionState.UNINSTALLED; this.emit('extension-state-changed', extension); - delete ExtensionUtils.extensions[extension.uuid]; + delete this._extensions[extension.uuid]; return true; } @@ -217,7 +274,7 @@ var ExtensionManager = class { // Now, recreate the extension and load it. let newExtension; try { - newExtension = ExtensionUtils.createExtensionObject(uuid, dir, type); + newExtension = this.createExtensionObject(uuid, dir, type); } catch (e) { this.logExtensionError(uuid, e); return; @@ -227,7 +284,7 @@ var ExtensionManager = class { } _callExtensionInit(uuid) { - let extension = ExtensionUtils.extensions[uuid]; + let extension = this._extensions[uuid]; let dir = extension.dir; if (!extension) @@ -328,7 +385,7 @@ var ExtensionManager = class { } _onSettingsWritableChanged() { - for (let uuid in ExtensionUtils.extensions) { + for (let uuid in this._extensions) { let extension = ExtensionUtils.extensions[uuid]; this._updateCanChange(extension); this.emit('extension-state-changed', extension); @@ -340,8 +397,8 @@ var ExtensionManager = class { // extensions when allowed by the sessionMode, so // temporarily disable them all this._enabledExtensions = []; - for (let uuid in ExtensionUtils.extensions) - this.reloadExtension(ExtensionUtils.extensions[uuid]); + for (let uuid in this._extensions) + this.reloadExtension(this._extensions[uuid]); this._enabledExtensions = this._getEnabledExtensions(); if (Main.sessionMode.allowExtensions) { @@ -363,11 +420,30 @@ var ExtensionManager = class { this._enabledExtensions = this._getEnabledExtensions(); - let finder = new ExtensionUtils.ExtensionFinder(); - finder.connect('extension-found', (finder, extension) => { + let perUserDir = Gio.File.new_for_path(global.userdatadir); + FileUtils.collectFromDatadirs('extensions', true, (dir, info) => { + let fileType = info.get_file_type(); + if (fileType != Gio.FileType.DIRECTORY) + return; + let uuid = info.get_name(); + let existing = this._extensions[uuid]; + if (existing) { + log(`Extension ${uuid} already installed in ${existing.path}. ${dir.get_path()} will not be loaded`); + return; + } + + let extension; + let type = dir.has_prefix(perUserDir) + ? ExtensionType.PER_USER + : ExtensionType.SYSTEM; + try { + extension = this.createExtensionObject(uuid, dir, type); + } catch (e) { + logError(e, `Could not load extension ${uuid}`); + return; + } this.loadExtension(extension); }); - finder.scanExtensions(); } _enableAllExtensions() { diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js index 9aeeaceb4..b99b701e1 100644 --- a/js/ui/lookingGlass.js +++ b/js/ui/lookingGlass.js @@ -624,7 +624,7 @@ var Extensions = class Extensions { this._extensionsList.add(this._noExtensions); this.actor.add(this._extensionsList); - for (let uuid in ExtensionUtils.extensions) + for (let uuid in Main.extensionManager.extensions) this._loadExtension(null, uuid); Main.extensionManager.connect('extension-loaded', @@ -632,7 +632,7 @@ var Extensions = class Extensions { } _loadExtension(o, uuid) { - let extension = ExtensionUtils.extensions[uuid]; + let extension = Main.extensionManager.extensions[uuid]; // There can be cases where we create dummy extension metadata // that's not really a proper extension. Don't bother with these. if (!extension.metadata.name) diff --git a/js/ui/main.js b/js/ui/main.js index 1566d2fe1..2fd49962e 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -228,6 +228,7 @@ function _initializeUI() { ExtensionDownloader.init(); extensionManager = new ExtensionSystem.ExtensionManager(); + extensionManager.init(); if (sessionMode.isGreeter && screenShield) { layoutManager.connect('startup-prepared', () => { diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js index 424aef567..2288d0cfd 100644 --- a/js/ui/shellDBus.js +++ b/js/ui/shellDBus.js @@ -255,7 +255,7 @@ var GnomeShellExtensions = class { ListExtensions() { let out = {}; - for (let uuid in ExtensionUtils.extensions) { + for (let uuid in Main.extensionManager.extensions) { let dbusObj = this.GetExtensionInfo(uuid); out[uuid] = dbusObj; } @@ -263,12 +263,12 @@ var GnomeShellExtensions = class { } GetExtensionInfo(uuid) { - let extension = ExtensionUtils.extensions[uuid] || {}; + let extension = Main.extensionManager.extensions[uuid] || {}; return ExtensionUtils.serializeExtension(extension); } GetExtensionErrors(uuid) { - let extension = ExtensionUtils.extensions[uuid]; + let extension = Main.extensionManager.extensions[uuid]; if (!extension) return []; @@ -304,7 +304,7 @@ var GnomeShellExtensions = class { } ReloadExtension(uuid) { - let extension = ExtensionUtils.extensions[uuid]; + let extension = Main.extensionManager.extensions[uuid]; if (!extension) return;